if _G['select'](2, _G['UnitClass']("player")) ~= "DRUID" then return end

local _G = _G
local UnitBuff = _G['UnitBuff']
local GetTime = _G['GetTime']
local UnitIsConnected = _G['UnitIsConnected']
local UnitIsDead = _G['UnitIsDead']
local UnitExists = _G['UnitExists']
local GetPrimaryTalentTree = _G['GetPrimaryTalentTree']
local strsplit = _G['strsplit']
local CreateFrame = _G['CreateFrame']
local GetSpellInfo = _G['GetSpellInfo']

local defaultConfig = {
	version = 1,
	point = 'CENTER',
	relPoint = 'CENTER',
	width = 316,
	height = 15,
	xoff = 0,
	yoff = -60,
	fontSize = 10,
	locked = true,
	warnTime = 4,
	alarmTime = 2,
	colors = {
		[1] = {1, 0, 1},
		[2] = {0, 1, 1},
		[3] = {0, 1, 0},
		[4] = {1, 1, 0},
		[5] = {1, 0, 0},
		[6] = {0.5, 0, 0},
	}
}

local cfg

local font, tex

if ElvUI then
	local _, c = unpack(ElvUI)
	font = c.media.font
	tex = c.media.normTex
else
	tex = [=[Interface\TargetingFrame\UI-StatusBar]=]
	font = [=[Fonts\ARIALN.ttf]=]
end

local frame = CreateFrame('Frame')

local unitID = 'focus'

local debug = false

if debug then
	_G['LbTracker'] = frame
end

local visible = false

local lbname = _G['GetSpellInfo'](33763)

local bcr, bcg, bcb -- normal border color

local function dpr(...)
	if debug then
		print(...)
	end
end

function frame:CreateFrame()
	if self.bar then
		-- work around multiple PLAYER_ENTERING_WORLD
		return
	end

	if ElvUI then
		self:SetTemplate('Default', true)
	else
		self:SetBackdrop({
		  bgFile = [[Interface\BUTTONS\WHITE8X8]],
		  edgeFile = [[Interface\BUTTONS\WHITE8X8]],
		  tile = false, tileSize = 0, edgeSize = 1,
		  insets = {left = -1, right = -1, top = -1, bottom = -1}
		})
		self:SetBackdropBorderColor(.23, .23, .23, 1)
		self:SetBackdropColor(.1, .1, .1, 1)
	end
	bcr, bcg, bcb = self:GetBackdropBorderColor()
	self:SetFrameStrata("MEDIUM")
	self:SetFrameLevel(30)

	self.bar = CreateFrame('StatusBar', 'PsLbTracker', self)
	self.bar:ClearAllPoints()
	self.bar:SetPoint('CENTER', frame, 'CENTER', 0, 0)
	self.bar:SetStatusBarTexture(tex)
	self.bar:SetMinMaxValues(0, 100)
	self.bar:SetValue(0)
	self:SetSbColor(0)

	self.value = self.bar:CreateFontString(nil, 'OVERLAY', self.bar)
	self.value:SetPoint('LEFT', self.bar, 'LEFT', 2, 0)
	self.value:SetJustifyH('LEFT')
	self.value:SetTextColor(1, 1, 1)

	self.spark = self.bar:CreateTexture(nil, 'OVERLAY', nil)
	self.spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
	self.spark:SetWidth(12)
	self.spark:SetBlendMode('ADD')
	self.spark:Show()

	self:SetScript('OnDragStart', self.StartMoving)
	self:SetScript('OnDragStop', self.StopMovingOrSizing)

	self:ApplyConfig()
	self:Hide()
	if not cfg.locked then
		self:ApplyLock()
	end
end

function frame:ApplyConfig()
	self:SetWidth(cfg.width)
	self:SetHeight(cfg.height)
	self:SetPoint(cfg.point, 'UIParent', cfg.relPoint, cfg.xoff, cfg.yoff)

	self.bar:SetWidth(cfg.width - 2)
	self.bar:SetHeight(cfg.height - 2)
	self.spark:SetHeight(cfg.height*1.85)

	self.value:SetFont(font, cfg.fontSize, 'OUTLINE')
end

_G['SLASH_LBTRACKER1'] = '/lbt'
_G['SlashCmdList'].LBTRACKER = function(input)
	local cmd, arg = strsplit(" ", input:lower(), 2)
	if cmd == 'lock' or cmd == 'unlock' or cmd == 'drag' or cmd == 'move' then
		cfg.locked = not cfg.locked
		frame:ApplyLock()
		return
	end

	if cmd == 'width' then
		cfg.width = tonumber(arg)
	elseif cmd == 'height' then
		cfg.height = tonumber(arg)
	elseif cmd == 'fontsize' then
		cfg.fontSize = tonumber(arg)
	elseif cmd == 'hcenter' then
		cfg.xoff = 0
	else
		return
	end
	frame:ApplyConfig()
end

function frame:ApplyLock()
	if cfg.locked then
		local point, _, relativePoint, xOfs, yOfs = self:GetPoint()

		cfg.point = point
		cfg.relPoint = relativePoint
		cfg.xoff = xOfs
		cfg.yoff = yOfs

		self:StopMovingOrSizing()

		self:SetMovable(false)
		self:EnableMouse(false)
		self:RegisterForDrag()

		if not visible then
			self:Hide()
		end
	else
		self:SetMovable(true)
		self:EnableMouse(true)
		self:RegisterForDrag('LeftButton')
		self:Show()
	end
end

function frame:HandleEvent(event, ...)
	if event == 'PLAYER_ENTERING_WORLD' then
		cfg = _G['LbtConfig']
		if not cfg then
			cfg = defaultConfig
			_G['LbtConfig'] = cfg
		end
		self:CreateFrame()
		return
	end

	if event ~= 'UNIT_AURA' then
		self:Setup()
	end

	if visible then
		self:UpdateView()
	end
end

local lastUpdate = 0
local updateInterval = 0.01

function frame:update(elapsed)
	lastUpdate = lastUpdate + elapsed
	if lastUpdate > updateInterval then
		lastUpdate = 0
		if visible then
			self:UpdateView()
		end
	end
end

function frame:Setup()
	local newValue
	if not UnitExists(unitID) or (GetPrimaryTalentTree() ~= 3) then
		newValue = false
	else
		newValue = true
	end

	if visible == newValue then
		return
	end

	visible = newValue

	if visible then
		self:UpdateView()
		self:Show()
		self:SetScript('OnUpdate', self.update)
	else
		self:SetScript('OnUpdate', nil)
		self:Hide()
	end
end

local sbColor = -1
function frame:SetSbColor(newColor)
	if newColor ~= sbColor then
		sbColor = newColor
		if sbColor == 0 then
			self.bar:SetStatusBarColor(0, 0, 0)
		else
			self.bar:SetStatusBarColor(unpack(cfg.colors[sbColor]))
			local r, g, b
			if sbColor > 3 then
				r, g, b = unpack(cfg.colors[sbColor])
			else
				r, g, b = bcr, bcg, bcb
			end
			self:SetBackdropBorderColor(r, g, b, 1)
		end
	end
end

local lastValue = -1
local lastDuration = 0
local lastSoundTime = 0
local lastLbTime = 0

function frame:UpdateView()
	local _, _, _, count, _, duration, expires = UnitBuff(unitID, lbname)

	local now = GetTime()

	count = count or 0
	duration = duration or 0
	expires = expires

	if not expires then
		expires = now - 1
	end

	local remain

	if (duration ~= lastDuration) then
		lastDuration = duration
		self.bar:SetMinMaxValues(0, (duration * 100))
	end

	local ramain, newValue

	remain = expires - now
	if remain < 0 then
		remain = 0
	end

	local color
	local unitConnectedAndNotDead = UnitIsConnected(unitID) and not UnitIsDead(unitID)

	if remain < cfg.alarmTime then
		if not UnitIsConnected(unitID) or UnitIsDead(unitID) then
			color = 0
		elseif remain == 0 then
			color = 6
		else
			color = 5
		end
	elseif remain < cfg.warnTime then
		color = 4
	else
		color = count
	end
	self:SetSbColor(color)

	newValue = (remain * 100)
	if newValue ~= lastValue then
		self.bar:SetValue(newValue)
		lastValue = newValue
		if lastValue == 0 then
			self.spark:Hide()
		else
			self.spark:SetPoint('CENTER', self.bar, 'LEFT', self.bar:GetWidth() * remain / duration, 0)
			self.spark:Show()
		end
	end

	local msg

	if remain < 0.001 then
		if not UnitIsConnected(unitID) then
			msg = 'D/C'
		elseif UnitIsDead(unitID) then
			msg = 'DEAD'
		else
			msg = string.upper(lbname)..'!'
		end
		if (now - lastLbTime > 1.5)
			and (now - lastSoundTime > 3)
			and InCombatLockdown()
			and UnitIsConnected(unitID)
			and not UnitIsDead(unitID) then
			lastSoundTime = now
			PlaySoundFile([[Interface\AddOns\LbTracker\media\warn.mp3]])
		end
	else
		lastLbTime = now
		msg = string.format('[%d] %.1f', count, remain)
	end
	self.value:SetText(msg)
end

frame:SetScript('OnEvent', frame.HandleEvent)
frame:RegisterEvent('PLAYER_ENTERING_WORLD')
frame:RegisterEvent('UNIT_CONNECTION')
frame:RegisterEvent('PLAYER_FOCUS_CHANGED')
frame:RegisterEvent('UNIT_AURA')
frame:RegisterEvent('PLAYER_TALENT_UPDATE')
